package com.aso.common.utils;

import android.content.Context;
import android.os.Environment;
import android.os.storage.StorageManager;
import android.text.TextUtils;

import com.aso.common.global.CommonGlobal;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by itsdf07 on 2017/3/6 14:56.
 * E-Mail: 923255742@qq.com
 * GitHub: https://github.com/itsdf07
 */

public class FileUtils {
    private static final String FROM = "[" + FileUtils.class.getSimpleName() + "] ";
    public static String INNERSDPATH = Environment.getExternalStorageDirectory().getAbsolutePath() + CommonGlobal.BASE_PATH;

    /**
     * 删除垃圾文件完成后（不论成功与否，只要跳出删除）后的回调
     */
    public interface IDelJunkFileCallback {
        /**
         * 删除完成之后的回调
         */
        void callback();
    }

    private FileUtils() {
        throw new UnsupportedOperationException("Sorry,Instantiation [FileUtils.java] Failure!");
    }


    /**
     * 判断是否是【目录】
     *
     * @param dirPath 目录路径
     * @return {@code true}: 是<br>{@code false}: 否
     */
    public static boolean isDir(String dirPath) {
        File file = getFileByPath(dirPath);
        return isDir(file);
    }

    /**
     * 判断是否是【目录】
     *
     * @param file 文件
     * @return {@code true}: 是<br>{@code false}: 否
     */
    public static boolean isDir(File file) {
        return isFileExists(file) && file.isDirectory();
    }

    /**
     * 判断是否是【文件】
     *
     * @param filePath 文件路径
     * @return {@code true}: 是<br>{@code false}: 否
     */
    public static boolean isFile(String filePath) {
        File file = getFileByPath(filePath);
        return isFile(file);
    }

    /**
     * 判断是否是【文件】
     *
     * @param file 文件
     * @return {@code true}: 是<br>{@code false}: 否
     */
    public static boolean isFile(File file) {
        return isFileExists(file) && file.isFile();
    }

    /**
     * 判断【文件】是否存在
     *
     * @param filePath 文件路径
     * @return {@code true}: 存在<br>{@code false}: 不存在
     */
    public static boolean isFileExists(String filePath) {
        File file = getFileByPath(filePath);
        return isFileExists(file);
    }

    /**
     * 判断【文件】是否存在
     *
     * @param file 文件
     * @return {@code true}: 存在<br>{@code false}: 不存在
     */
    public static boolean isFileExists(File file) {
        return null != file && file.exists();
    }

    /**
     * 判断【目录】是否存在，不存在则判断是否创建成功
     * PS：直接创建到目标目录，如 内卡路径 + "aso/aso/aso"，则直接创建三个文件夹
     *
     * @param dirPath 目录路径
     * @return {@code true}: 存在或创建成功<br>{@code false}: 不存在或创建失败
     */
    public static boolean createOrExistsDir(String dirPath) {
        File file = getFileByPath(dirPath);
        return createOrExistsDir(file);
    }

    /**
     * 判断【目录】是否存在，不存在则判断是否创建成功
     *
     * @param file 文件
     * @return {@code true}: 存在或创建成功<br>{@code false}: 不存在或创建失败
     */
    public static boolean createOrExistsDir(File file) {
        // 如果存在，是目录则返回true，是文件则返回false，不存在则返回是否创建成功
        return file != null && (file.exists() ? file.isDirectory() : file.mkdirs());
    }

    /**
     * 判断【文件】是否存在，不存在则判断是否创建成功
     *
     * @param filePath 文件路径
     * @return {@code true}: 存在或创建成功<br>{@code false}: 不存在或创建失败
     */
    public static boolean createOrExistsFile(String filePath) {
        File file = getFileByPath(filePath);
        return createOrExistsFile(file);
    }

    /**
     * 判断【文件】是否存在，不存在则判断是否创建成功
     *
     * @param file 文件
     * @return {@code true}: 存在或创建成功<br>{@code false}: 不存在或创建失败
     */
    public static boolean createOrExistsFile(File file) {
        if (null == file) {
            return false;
        }
        // 如果存在，是文件则返回true，是目录则返回false
        if (file.exists()) {
            return file.isFile();
        }

        if (!createOrExistsDir(file.getParentFile())) {//创建文件目录
            return false;
        }
        try {
            return file.createNewFile();//创建文件
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 判断【文件】是否存在，存在则在创建之前删除
     *
     * @param filePath 文件路径
     * @return {@code true}: 创建成功<br>{@code false}: 创建失败
     */
    public static boolean createFileByDeleteOldFile(String filePath) {
        File file = getFileByPath(filePath);
        return createFileByDeleteOldFile(file);
    }

    /**
     * 判断【文件】是否存在，存在则在创建之前删除
     *
     * @param file 文件
     * @return {@code true}: 创建成功<br>{@code false}: 创建失败
     */
    public static boolean createFileByDeleteOldFile(File file) {
        if (null == file) {
            return false;
        }

        // 文件存在并且删除失败返回false
        if (file.exists() && file.isFile()) {
            String filePath = file.getPath() + System.currentTimeMillis();
            File oldFile = new File(filePath);
            if (rename(file, oldFile.getName())) {
                delJunkFile(oldFile, false, null);
            } else {
                return false;
            }

        }
        // 创建目录失败返回false
        if (!createOrExistsDir(file.getParentFile())) {
            return false;
        }
        try {
            return file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 开启线程删除【文件】
     * */
    /**
     * @param file       需要删除的垃圾文件(单个个)
     * @param needRename 是否需要重命名的方式来删除
     * @param callback   文件删除完成之后的回调，不需要的话可以传入null
     */
    public static void delJunkFile(final File file, final boolean needRename, final IDelJunkFileCallback callback) {
        if (!isFileExists(file)) {
            return;
        }
        List<File> list = new ArrayList<>();
        list.add(file);
        delJunkFile(list, needRename, callback);
    }

    /**
     * 开启线程删除【文件】
     * */
    /**
     * @param files      需要删除的垃圾文件(多个)
     * @param needRename 是否需要重命名的方式来删除
     * @param callback   文件删除完成之后的回调，不需要的话可以传入null
     */
    public static void delJunkFile(final List<File> files, final boolean needRename, final IDelJunkFileCallback callback) {
        if (null == files || files.size() == 0) {
            return;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (File file : files) {
                    if (isFileExists(file)) {
                        if (needRename) {
                            File fileRename = new File(file.getPath() + System.currentTimeMillis());
                            if (file.renameTo(fileRename)) {
                                file = fileRename;
                            }
                        }
                        file.delete();
                    }
                }
                if (null != callback) {
                    callback.callback();
                }
            }
        }).start();
    }


    /**
     * 重命名【文件】
     *
     * @param filePath 文件路径
     * @param newName  新名称
     * @return {@code true}: 重命名成功<br>{@code false}: 重命名失败
     */
    public static boolean rename(String filePath, String newName) {
        File file = getFileByPath(filePath);
        return rename(file, newName);
    }

    /**
     * 重命名文件
     *
     * @param file    文件
     * @param newName 新名称
     * @return {@code true}: 重命名成功<br>{@code false}: 重命名失败
     */
    public static boolean rename(File file, String newName) {
        // 文件为空返回false
        if (null == file) {
            return false;
        }
        // 文件不存在返回false
        if (!file.exists()) {
            return false;
        }
        // 新的文件名为空返回false
        if (TextUtils.isEmpty(newName)) {
            return false;
        }
        // 如果文件名没有改变返回true
        if (newName.equals(file.getName())) {
            return true;
        }
        File newFile = new File(file.getParent() + File.separator + newName);
        // 如果重命名的文件已存在返回false
        return !newFile.exists() && file.renameTo(newFile);
    }

    /**
     * 信息写入文件
     *
     * @param file    写入的文件
     * @param content 写入的数据
     * @param append  是否覆盖写入
     * @return {@code true}: 信息写入成功<br>{@code false}: 信息写入失败
     */
    public static boolean write2File(File file, String content, boolean append) {
        content = StringUtils.null2Length0(content);
        byte[] aData = content.getBytes();
        return write2File(file, aData, append);
    }

    /**
     * 信息写入文件
     *
     * @param file   写入的文件
     * @param aData  写入的数据
     * @param append 是否覆盖写入
     * @return {@code true}: 信息写入成功<br>{@code false}: 信息写入失败
     */
    private static boolean write2File(File file, byte[] aData, boolean append) {
        if (!createOrExistsFile(file)) {
            //写入文件不存在且创建失败时return false
            return false;
        }
        OutputStream out = null;
        boolean ok = false;
        try {
            out = new FileOutputStream(file, append);
            out.write(aData);
            ok = true;
        } catch (Exception e) {
//            LogUtils.e(FROM + "File is written to failure ：", e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                }
            }
        }
        return ok;
    }

    /**
     * 获取内置sd卡路径，<br/>
     * 目前个人认为可以移除就是外卡，不能移除就是内卡，只经过大量试验，没有任何依据！此处需慎重！！！
     *
     * @param context
     * @return 内卡路径
     */
    public static String getInnerSDPath(Context context) {

        int currentapiVersion = android.os.Build.VERSION.SDK_INT;
        if (currentapiVersion >= 12) {
            try {
                StorageManager manager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
                /************** StorageManager的方法 ***********************/
                Method getVolumeList = StorageManager.class.getMethod("getVolumeList");
                Method getVolumeState = StorageManager.class.getMethod("getVolumeState", String.class);

                Object[] Volumes = (Object[]) getVolumeList.invoke(manager);
                String state = null;
                String path = null;

                for (Object volume : Volumes) {
                    /************** StorageVolume的方法 ***********************/
                    Method getPath = volume.getClass().getMethod("getPath");
                    path = (String) getPath.invoke(volume);
                    state = (String) getVolumeState.invoke(manager, getPath.invoke(volume));

                    /**
                     * 是否可以移除(内置sdcard) TODO:
                     * 目前个人认为可以移除就是外卡，不能移除就是内卡，只经过大量试验，没有任何依据！此处需慎重！！！
                     */
                    Method isRemovable = volume.getClass().getMethod("isRemovable");
                    boolean removable = (Boolean) isRemovable.invoke(volume);

                    if (null != path && null != state && state.equals(Environment.MEDIA_MOUNTED)) {
                        if (false == removable) {
                            return path;
                        }
                    }
                }
            } catch (Exception e) {
                return "";
            }
        }
        // 得到存储卡路径
        File sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); // 判断sd卡
        // 或可存储空间是否存在
        if (sdCardExist) {
            sdDir = Environment.getExternalStorageDirectory();// 获取sd卡或可存储空间的跟目录
            return sdDir.toString();
        }

        return "";
    }

    /**
     * 根据文件路径获取文件
     *
     * @param filePath 文件路径
     * @return 文件
     */
    public static File getFileByPath(String filePath) {
        return TextUtils.isEmpty(filePath.trim()) ? null : new File(filePath);
    }

    /**
     * 获取assets目录下的资源
     *
     * @param context
     * @param file    文件名，如"xxx.txt"
     * @return
     */
    public static String getAssetsResource(Context context, String file) {
        InputStream inputStream = null;
        try {
            inputStream = context.getResources().getAssets().open(file);//读取assets/下的文件
        } catch (IOException e) {
            e.printStackTrace();
        }
        return getString(inputStream);
    }

    /**
     * 获取路径下的所有文件集，使用时注意判 null
     *
     * @param path
     * @return
     */
    public static File[] getFileList(String path) {
        File file = new File(path);
        File[] fileLists = file.listFiles();
        return fileLists;
    }

    /**
     * 获取Raw目录下的音频文件
     *
     * @param context
     * @param raw     R.raw.xxx
     * @return
     */
    public static String getRawResource(Context context, int raw) {
        InputStream inputStream = context.getResources().openRawResource(raw);//读取res/raw/下的文件
        return getString(inputStream);
    }

    private static String getString(InputStream inputStream) {
        InputStreamReader inputStreamReader = null;
        try {
            inputStreamReader = new InputStreamReader(inputStream, "utf-8");
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
        BufferedReader reader = new BufferedReader(inputStreamReader);
        StringBuffer sb = new StringBuffer("");
        String line;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line);
                sb.append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();
    }


}
